package com.ly.base.jdbc.dao;

import com.ly.base.jdbc.JDBC;
import com.ly.base.jdbc.annotation.Column;
import com.ly.base.jdbc.annotation.Id;
import com.ly.base.jdbc.annotation.Table;
import com.ly.base.jdbc.utils.JDBCUtils;
import javafx.scene.control.Tab;
import lombok.Data;
import lombok.Getter;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Classname BaseDao
 * @Description TODO
 * @Date 2020/11/2 15:59
 * @Author 冷心影翼
 */
@Data
public class BaseDao<T,E> {

	private Connection connection;

	private Class<T> clazz;

	private Field idField;

	private String tableName;

	private String idName;

	public BaseDao() {
		connection = JDBCUtils.getConnection();
		setClazz();
		setId();
		setTableType();
	}

	//更新和删除
	public int updateBySql(String sql,Object... args) throws SQLException {
		PreparedStatement preparedStatement = connection.prepareStatement(sql);
        for (int i = 1; i <= args.length; i++) {
            preparedStatement.setObject(i,args[i-1]);
        }
        int i = preparedStatement.executeUpdate();
        return i;
    }





    //查询
	public List<T> selectBySql(String sql,Object... args) {
		try {
			List<T> list = new ArrayList<>();
			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			for(int i=1;i<=args.length;i++) {
				preparedStatement.setObject(i,args[i-1]);
			}
			ResultSet resultSet = preparedStatement.executeQuery();
			ResultSetMetaData r = resultSet.getMetaData();
			int columnCount = r.getColumnCount();

			Field[] declaredFields = clazz.getDeclaredFields();
			while (resultSet.next()) {
				T t = clazz.newInstance();
				//遍历每列
				for(int i=1;i<=columnCount;i++) {
				    //匹配字段
					for(Field f:declaredFields) {
						Column column = f.getAnnotation(Column.class);
						Id id = f.getAnnotation(Id.class);
						//不是数据库字段
						if(column == null && id == null) {
							continue;
						}
						String name = f.getName();
						//id转换驼峰命名
						if(id!=null) {
							if(StringUtils.isEmpty(id.value()) ){
								name = replaceName(name,id.hump());
							}else {
								name = replaceName(id.value(),id.hump());
							}
						}
						//列转换驼峰命名
						if(column!=null) {
							if(StringUtils.isEmpty(column.value()) ){
								name = replaceName(name,column.hump());
							}else {
								name = replaceName(column.value(),column.hump());
							}
						}
						if(!r.getColumnName(i).equals(name)) {
							continue;
						}
						Object object = resultSet.getObject(i);
						f.setAccessible(true);
						f.set(t,object);
					}
				}
				list.add(t);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public int deleteById(E id) {
		String sql = "delete from "+tableName+" where "+idName+ " = ?";
		try{
			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setObject(1,id);
			return preparedStatement.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
		}
		return 0;
	}

	public T selectById(E id) {
		String sql = "select * from "+tableName+" where "+idName+ " = ?";
		T t = null;
		try{

			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			preparedStatement.setObject(1,id);
			ResultSet resultSet = preparedStatement.executeQuery();
			if(!resultSet.next()) {
				return t;
			}

			t = clazz.newInstance();

			//获取数据库字段
			Field[] declaredFields = clazz.getDeclaredFields();
			for(Field f:declaredFields) {
				Column column = f.getAnnotation(Column.class);
				if(column == null) {
					continue;
				}
				//处理别名
				String name = f.getName();
				if(StringUtils.isEmpty(column.value()) ){
					name = replaceName(name,column.hump());
				}else {
					name = replaceName(column.value(),column.hump());
				}


				Object object = resultSet.getObject(name);
				f.setAccessible(true);
				f.set(t,object);
			}

			idField.set(t,id);
			return t;

		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}

	//update table set f1=?, f2 = ? where f3=?
	public int updateById(T t,E id) {
		String sql = "update "+tableName+" set";
		try{

			//获取数据库字段,设置字段
			Field[] declaredFields = clazz.getDeclaredFields();

			for(Field f:declaredFields) {
				Column column = f.getAnnotation(Column.class);
				if(column == null) {
					continue;
				}

				String name = f.getName();
				if(StringUtils.isEmpty(column.value()) ){
					name = replaceName(name,column.hump());
				}else {
					name = replaceName(column.value(),column.hump());
				}
				sql += (" "+name+" = ?,");
			}

			//设置值
			sql = sql.substring(0,sql.length()-1);
			sql += " where "+idName+ " = ?";
			System.out.println(sql);
			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			int i = 0;
			for(Field f:declaredFields) {
				Column column = f.getAnnotation(Column.class);
				if(column == null) {
					continue;
				}
				f.setAccessible(true);
				Object o = f.get(t);
				preparedStatement.setObject(++i,o);
			}
			preparedStatement.setObject(++i,id);
			return preparedStatement.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
		}
		return 0;
	}


	public int insert(T t) {
		try{
			Field[] declaredFields = clazz.getDeclaredFields();
			//拼接插入语句
			StringBuilder sql = new StringBuilder("insert into "+tableName+" values (?");
			String fieldsSql = getFieldsSql(sql.toString(),",?");

			fieldsSql+= ")";
			System.out.println(fieldsSql);

			PreparedStatement preparedStatement = connection.prepareStatement(fieldsSql);
			int i = 0;
			for(Field f:declaredFields) {
				Column column = f.getAnnotation(Column.class);
				Id id = f.getAnnotation(Id.class);
				if(column == null && id == null) {
					continue;
				}
				f.setAccessible(true);
				Object o = f.get(t);
				preparedStatement.setObject(++i,o);
			}
			return preparedStatement.executeUpdate();
		}catch(Exception e){
			e.printStackTrace();
		}
		return 0;
	}

	//insert into table values(?,?,?);
	//update table set f1=?, f2 = ? where f3=?
	private String getFieldsSql(String start,String str) {
		StringBuilder fieldSql = new StringBuilder(start);
		//获取数据库字段,设置字段
		Field[] declaredFields = clazz.getDeclaredFields();

		for(Field f:declaredFields) {
			Column column = f.getAnnotation(Column.class);
			if(column == null) {
				continue;
			}

			String name = f.getName();
			if(StringUtils.isEmpty(column.value()) ){
				name = replaceName(name,column.hump());
			}else {
				name = replaceName(column.value(),column.hump());
			}
			fieldSql.append(str);
		}
		return fieldSql.toString();
	}

	/*
		实体类 注入
	 */
	private void setClazz() {
		Type genericSuperclass = getClass().getGenericSuperclass();
		ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
		Type actualTypeArguments = parameterizedType.getActualTypeArguments()[0];
		clazz = (Class<T>) actualTypeArguments;
	}

	/*
		id 注入
	 */
	private void setId()  {
		Field[] fields = clazz.getDeclaredFields();
		Id id = null;
		for (Field f: fields ) {
			id = f.getAnnotationsByType(Id.class)[0];
			if(id != null) {
		    	idField = f;
		    	idField.setAccessible(true);
		    	break;
		    }
		}
		if(id == null) {
			throw new RuntimeException("Need a Id Annotation");
		}
		if(StringUtils.isEmpty(id.value()) ){
			String name = idField.getName();
			idName = replaceName(name,id.hump());
		}else {
			idName = replaceName(id.value(),id.hump());
		}
	}

	/*
		表名注入
	 */
	private void setTableType() {
		Table annotation = clazz.getAnnotation(Table.class);
		if(annotation == null) {
			throw new RuntimeException("Need a table Annotation");
		}else {
			if(StringUtils.isEmpty(annotation.value()) ){
				String name = clazz.getSimpleName();
				tableName = replaceName(name,annotation.hump());
			}else {
				tableName = replaceName(annotation.value(),annotation.hump());
			}
		}
	}

	/*
		驼峰命名
	 */
	private String replaceName(String name,boolean change) {
		if(change) {
			StringBuilder sb = new StringBuilder("");
			char[] arr = name.toCharArray();
			for(int i=0;i<name.length();i++) {
				if (arr[i] >= 65 && arr[i] <= 91 && i!=0) {
					sb.append("_");
				}
				sb.append((arr[i]+"").toLowerCase());
			}
			name = sb.toString();
		}
		return name;
	}

	/*
		反向驼峰命名
	 */
	private String replaceNameReverse(String name,boolean change) {
		if(change) {
			StringBuilder sb = new StringBuilder("");
			char[] arr = name.toCharArray();
			for(int i=0;i<name.length();i++) {
				if (arr[i] == '_') {
					sb.append((arr[i+1]+"").toUpperCase());
					continue;
				}
				sb.append((arr[i]+""));
			}
			name = sb.toString();
		}
		return name;
	}
}
